package ws

import (
	"encoding/json"
	"log"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// Client WebSocket客户端
type Client struct {
	ID     uint
	Conn   *websocket.Conn
	Send   chan []byte
	Hub    *Hub
	mu     sync.Mutex
	closed bool
}

// Message 消息结构
type Message struct {
	Type       string      `json:"type"`
	FromUserID uint        `json:"from_user_id,omitempty"`
	Content    string      `json:"content,omitempty"`
	Data       interface{} `json:"data,omitempty"`
	CreatedAt  time.Time   `json:"created_at,omitempty"`
}

// NewClient 创建新的客户端
func NewClient(id uint, conn *websocket.Conn, hub *Hub) *Client {
	return &Client{
		ID:   id,
		Conn: conn,
		Send: make(chan []byte, 256),
		Hub:  hub,
	}
}

// ReadPump 处理读取消息
func (c *Client) ReadPump() {
	defer func() {
		c.Hub.Unregister <- c
		c.Close()
	}()

	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("error: %v", err)
			}
			break
		}

		var msg Message
		if err := json.Unmarshal(message, &msg); err != nil {
			log.Printf("error unmarshaling message: %v", err)
			continue
		}

		// 处理消息
		if msg.Type == "message" {
			msg.FromUserID = c.ID
			msg.CreatedAt = time.Now()
			if newMessage, err := json.Marshal(msg); err == nil {
				c.Hub.Broadcast <- newMessage
			}
		}
	}
}

// WritePump 处理发送消息
func (c *Client) WritePump() {
	defer func() {
		c.Close()
	}()

	for {
		select {
		case message, ok := <-c.Send:
			if !ok {
				c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			w, err := c.Conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			w.Write(message)

			if err := w.Close(); err != nil {
				return
			}
		}
	}
}

// Close 关闭连接
func (c *Client) Close() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if !c.closed {
		if c.Conn != nil {
			c.Conn.Close()
		}
		close(c.Send)
		c.closed = true
	}
}

// SendMessage 发送消息给客户端
func (c *Client) SendMessage(message []byte) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if !c.closed {
		select {
		case c.Send <- message:
		default:
			close(c.Send)
			c.closed = true
		}
	}
}
